﻿
using KnBinarySerializer.Field;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace KnBinarySerializer
{
    internal class ClassFormatterV2 : IFormatter
    {        
        public Type GetHandleType()
        {
            return typeof(object);
        }

        public byte GetKey()
        {
            return (byte)0;
        }
        public bool IsFixLen()
        {
            return false;
        }

        public int WriteBytes(BinarySerializeManager stream, object obj)
        {
            if (obj == null)
            {
                stream.Write(0);//写入0的字段数，视为0
                return 0;
            }

            Type type = obj.GetType();
            ClassSerial serial;//通过该序列取回属性的次序
            Dictionary<string, IClassField> fields = ClassSerialContext.GetFields(type);
            stream.Write(fields.Count);
            serial = stream.WriteClassSerial(type, fields);//写入类的序列
            foreach (var one in serial.Fields)
            {
                IClassField property = fields[one.Value];
                object objVal = property.GetValue(obj, null);
                if (objVal == null)
                    stream.WriteNull();
                else
                    stream.SerializeObject(objVal);//按次序写入各属性的值
            }

            return 0;
        }

        public object ReadBytes(BinarySerializeManager content, int maxLen, Type type)
        {
            //读取属性数量
            int fieldCnt = content.ReadInt();
            if (fieldCnt == 0)//null只会写入一个0
                return null;
            
            Dictionary<string, IClassField> fields = ClassSerialContext.GetFields(type);
            var serial = content.ReadClassSerial();
            
            object obj = ClassSerialContext.CreateObject(type);
            for (int index =0; index < fieldCnt; index++) 
            {                
                string name = serial.Fields[index];
                if (!fields.ContainsKey(name))//数据中有，但目标类型中不包含字段，需要跳过
                {
                    byte misKey = content.ReadByte();
                    IFormatter formatter = content.GetFormatter(misKey);
                    if (misKey == BinarySerializeManager.CLASS_FORMATTER_KEY)
                    {
                        //throw new KnBinaryException(misKey, $"无法获取长度，请为{type.Name}补充以下字段：{name}");
                        ClassFormatterV2 classFormatter = (ClassFormatterV2)formatter;
                        classFormatter.skipBytes(content);
                        continue;
                    }
                    formatter.ReadBytes(content, 0, null);
                    //int misLen = 0;
                    //if (formatter.IsFixLen())
                    //{                        
                    //    misLen = content.GetBytesLen(formatter.GetHandleType());
                    //    if (misLen == -1)
                    //        throw new Exception($"固定长度属性无法忽略，请定义{type.Name}.{name}[{formatter.GetHandleType().Name}]属性");
                    //}
                    //else
                    //{
                    //    misLen = content.ReadInt();
                    //}
                    //content.Skip(misLen);
                    continue;
                }
                IClassField property = fields[name];
                if (property.CanWrite)
                {
                    object objVal = content.DeSerializeObject(property.PropertyType);
                    property.SetValue(obj, objVal, null);
                }
                else
                {
                    //不能写的，视为子进行子项添加
                    object objVal = property.GetValue(obj, null);
                    if (objVal == null)
                        throw new Exception("不能写的属性，需要类自行初始化才能进行反序列化");
                    content.DeSerializeToObject(objVal);
                }
            }
            return obj;
        }

        public void skipBytes(BinarySerializeManager content)
        {
            //读取属性数量
            int fieldCnt = content.ReadInt();
            if (fieldCnt == 0)//null只会写入一个0
                return;

            //Dictionary<string, IClassField> fields = ClassSerialContext.GetFields(type);
            var serial = content.ReadClassSerial();
            //object obj = ClassSerialContext.CreateObject(type);
            for (int index = 0; index < fieldCnt; index++)
            {
                byte misKey = content.ReadByte();
                IFormatter formatter = content.GetFormatter(misKey);
                if (misKey == BinarySerializeManager.CLASS_FORMATTER_KEY)
                {
                    ClassFormatterV2 classFormatter = (ClassFormatterV2)formatter;
                    classFormatter.skipBytes(content);
                }
                else
                {
                    formatter.ReadBytes(content, 0, null);
                }
            }
        }
    }

    
}
